#include "Acceptor.h"
#include "Logger.h"
#include "InetAddress.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

static int createNonblocking()
{
    // SOCK_NONBLOCK:不让子进程打开父进程的打开的文件描述符
    int sockfd = ::socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,0);
    if(sockfd < 0)
    {
        // __FILE__ 哪个文件
        // __FUNCTION__ 函数名
        // __LINE__ 行号
        LOG_FATAL("%s:%s:%d listen sock create err:%d \n",__FILE__,__FUNCTION__,__LINE__,errno);
    }
}

Acceptor::Acceptor(EventLoop* loop,const InetAddress& listenAddr,bool reuseport)
    :loop_(loop)
    ,acceptSocket_(createNonblocking()) // socket
    ,acceptChannel_(loop_,acceptSocket_.fd())
    ,listenning_(false)
{
    acceptSocket_.setReuseAddr(true);
    acceptSocket_.sstReusePort(true);
    acceptSocket_.bindAddress(listenAddr); // bind
    // TcpServer::satrt() Acceptor.listen 有新用户的连接，要执行一个回调(connfd->channel->subloop)
    // baseLoop -> acceptChannel_(listenfd) ->
    acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead,this));
}
Acceptor::~Acceptor()
{
    acceptChannel_.disableAll();
    acceptChannel_.remove();
}


void Acceptor::listen()
{
    listenning_ = true;
    acceptSocket_.listen(); // 设置该sock为监听状态
    acceptChannel_.enableReading(); // 
    
}

// listenfd有事件发生了，就是有新用户连接了
void Acceptor::handleRead()
{
    InetAddress peerAddr;
    int connfd = acceptSocket_.accept(&peerAddr);
    if(connfd >= 0)
    {
        if(newConnectionCallback_)
        {
            newConnectionCallback_(connfd,peerAddr); // 轮询找到subLoop，唤醒，分发当前的新客户端的Channel
        }
        else
        {
            ::close(connfd);
        }
    }
    else
    {
        LOG_ERROR("%s:%s:%d accept err:%d \n",__FILE__,__FUNCTION__,__LINE__,errno);
        if(errno == EMFILE) // 每个进程能打开的文件描述符是有上限的
        {
            LOG_ERROR("%s:%s:%d sockfd reached limit! \n",__FILE__,__FUNCTION__,__LINE__);
        }
    }
}